package com.liuyk.commonlib.network;

import android.content.Context;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.KeyStore;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Collection;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

/**
 * 网络证书配置
 * <p>
 * Created by liuyakui on 2020/10/16.
 */
public class SSLSocketFactoryUtils {

    /**
     * 证书配置
     *
     * @param context 上下文
     * @param cerName 证书名称
     * @return SSL对象
     */
    public static SSLSocketFactory getSSLSocketFactory_Certificate(Context context, String cerName) {
        try {
            //获取X.509格式的内置证书
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null);
            Collection<? extends Certificate> cers = certificateFactory.generateCertificates(
                    context.getAssets().open(cerName));
            int index = 0;
            for (Certificate certificate : cers) {
                String certificateAlias = Integer.toString(index++);
                keyStore.setCertificateEntry(certificateAlias, certificate);
            }
            //用这个KeyStore去引导生成的TrustManager来提供验证
            final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            //用TrustManager生成SSLContext
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
            //SSLContext返回SSLSocketFactory
            return sslContext.getSocketFactory();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static class MyX509TrustManager implements X509TrustManager {
        private final Context context;
        private final String cerName;

        MyX509TrustManager(Context context, String cerName) {
            this.context = context;
            this.cerName = cerName;
        }

        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            if (chain == null) {
                throw new CertificateException("checkServerTrusted: X509Certificate array is null");
            }
            if (chain.length < 1) {
                if (!(null != authType && authType.equals("ECDHE_RSA"))) {
                    throw new CertificateException("checkServerTrusted: AuthType is not ECDHE_RSA");
                }
                //检查所有证书
                try {
                    TrustManagerFactory factory = TrustManagerFactory.getInstance("X509");
                    factory.init((KeyStore) null);
                    for (TrustManager trustManager : factory.getTrustManagers()) {
                        ((X509TrustManager) trustManager).checkServerTrusted(chain, authType);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                //获取本地证书中的信息
                String clientEncoded = "";
                String clientSubject = "";
                String clientIssUser = "";
                try {
                    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
                    InputStream inputStream = context.getAssets().open(cerName);
                    X509Certificate clientCertificate = (X509Certificate) certificateFactory.generateCertificate(inputStream);
                    clientEncoded = new BigInteger(1, clientCertificate.getPublicKey().getEncoded()).toString(16);
                    clientSubject = clientCertificate.getSubjectDN().getName();
                    clientIssUser = clientCertificate.getIssuerDN().getName();

                } catch (IOException e) {
                    e.printStackTrace();
                }

                //获取网络中的证书信息
                X509Certificate certificate = chain[0];
                PublicKey publicKey = certificate.getPublicKey();
                String serverEncoded = new BigInteger(1, publicKey.getEncoded()).toString(16);
                if (!clientEncoded.equals(serverEncoded)) {
                    throw new CertificateException("server's PublicKey is not equals to client's PublicKey");
                }
                String subject = certificate.getSubjectDN().getName();
                if (!clientSubject.equals(subject)) {
                    throw new CertificateException("server's subject is not equals to client's subject");
                }
                String issuser = certificate.getIssuerDN().getName();
                if (!clientIssUser.equals(issuser)) {
                    throw new CertificateException("server's issuser is not equals to client's issuser");
                }
            }
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    }

    public static SSLSocketFactory createTrustAllSSLFactory(TrustAllManager trustAllManager) {
        SSLSocketFactory ssfFactory = null;
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, new TrustManager[]{trustAllManager}, new SecureRandom());
            ssfFactory = sc.getSocketFactory();
        } catch (Exception ignored) {
            ignored.printStackTrace();
        }

        return ssfFactory;
    }

    public static class TrustAllManager implements X509TrustManager {
        @Override
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    }
}
